package com.hua.api.modules.finance.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.domain.AlipayTradeQueryModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.request.AlipayTradePrecreateRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.hua.api.core.constants.Status;
import com.hua.api.core.framework.config.SysConstant;
import com.hua.api.core.framework.util.exception.ApiError;
import com.hua.api.core.util.NumberUtil;
import com.hua.api.core.util.StringUtil;
import com.hua.api.core.util.ValidationUtil;
import com.hua.api.modules.finance.dao.UserAccountDao;
import com.hua.api.modules.finance.domain.UserAccount;
import com.hua.api.modules.finance.domain.UserAccountCharge;
import com.hua.api.modules.finance.domain.UserAccountHistory;
import com.hua.api.modules.finance.repository.UserAccountChargeRepository;
import com.hua.api.modules.finance.service.AliPayService;
import com.hua.api.modules.finance.service.UserAccountService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
@RequiredArgsConstructor
public class AliPayServiceImpl implements AliPayService {

    private final UserAccountChargeRepository userAccountChargeRepository;

    private final AlipayClient alipayClient;

    private final SysConstant sysConstant;

    private final UserAccountDao userAccountDao;

    private final UserAccountService userAccountService;

    public static final String success = "success";


    public static final String fail = "fail";

    /**
     * 参考文档： https://opendocs.alipay.com/open/00dn78?pathHash=fef00e6d
     * key：gmt_create------------value:2022-04-08 11:18:54
     * key：charset------------value:UTF8
     * key：seller_email------------value:huamoney@hua1000.com
     * key：subject------------value:店铺账户充值！
     * key：sign------------value:JjRlBRhbG41ck4y79KFr9LhME9HBc6zzSIaOY9kwPyt/LMM9CVuDVkNBa Cl tad5VDanikZwx2Ww55TG4PwdAJxQn2dWbMvGDgh2r Say1nHtU9jXEYgMCk69vfm6qTCe2hAD6 fFKhHMDdL7QTN2aAc35FHXOIloNhJZ6U11eirLIysgRlvm4zVaxZFBOy 4imjDOPjUNL2I9pp26z7uhnU72dKsWlsxW3ohaNUeHyHd3gfk65No96rsdsgiCXP/SbVXPEhGX VuoYtljhNBVU Zn2zamQUJ rWM/V9FqdOPN67SE8YtQroar1LA9Nz15WP5D1oyajpoZX16YiRw==
     * key：buyer_id------------value:2088002459706669
     * key：invoice_amount------------value:0.01
     * key：notify_id------------value:2022040800222111912006661451329716
     * key：fund_bill_list------------value:[{"amount":"0.01","fundChannel":"PCREDIT"}]
     * key：notify_type------------value:trade_status_sync
     * key：trade_status------------value:TRADE_SUCCESS
     * key：receipt_amount------------value:0.01
     * key：buyer_pay_amount------------value:0.01
     * key：app_id------------value:2021003126613063
     * key：sign_type------------value:RSA2
     * key：seller_id------------value:2088611570725161
     * key：gmt_payment------------value:2022-04-08 11:19:12
     * key：notify_time------------value:2022-04-08 11:19:12
     * key：version------------value:1.0
     * key：out_trade_no------------value:2022040811184882025309455993
     * key：total_amount------------value:0.01
     * key：trade_no------------value:2022040822001406661410350878
     * key：auth_app_id------------value:2021003126613063
     * key：buyer_logon_id------------value:fuj***@163.com
     * key：point_amount------------value:0.00
     * */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public String alipayNotify(Map<String, String> params) {
        try {
            boolean signVerified = AlipaySignature.certVerifyV1(params,sysConstant.getAlipayCertPath(),sysConstant.getCharset(),sysConstant.getSignType());
            if(signVerified){
                String tradeStatus = params.get("trade_status");
                log.info("AliPayServiceImpl.alipayNotify tradeStatus:{}", tradeStatus);
                if("TRADE_SUCCESS".equals(tradeStatus)){
                    // 充值成功

                    String outTradeNo = params.get("out_trade_no");
                    String tradeNo = params.get("trade_no");
                    return alipayNotifyTradeSuccess(outTradeNo,tradeNo);
                    // return alipayNotifyTradeSuccess(params);
                }else{
                    log.warn("alipayNotify tradeStatus={}",tradeStatus);
                    return fail;
                }
            }else {
                log.warn("支付宝回调验证，签名失败! ");
            }
        } catch (AlipayApiException e) {
            // throw new RuntimeException(e);
            return fail;
        }
        return fail;
    }

//    @Transactional(rollbackFor = Exception.class)
//    public String alipayNotifyTradeSuccess(Map<String, String> params){
//        // 我方订单号
//        String outTradeNo = params.get("out_trade_no");
//        // 支付宝订单号
//        String trade_no = params.get("trade_no");
//        UserAccountCharge uac = userAccountChargeRepository.findByOutTradeNo(outTradeNo);
//        log.info("outTradeNo={},tradeNo={}",outTradeNo,trade_no);
//        if(null==uac){
//            log.error("UserAccountCharge 充值记录不存在，无法");
//            return fail;
//        }
//        if(StringUtil.equals(uac.getState(),Status.LOGIC_N)){
//            log.info("AliPayServiceImpl.alipayNotifyTradeSuccess");
//            UserAccount account = userAccountDao.findUserAccountUseId(uac.getUserId());
//            if(null == account){
//                log.error("updateUserAccountChargeWithNotifyWithAlipay 充值账户信息不存在! userId=[{}]",uac.getUserId());
//                return "fail";
//            }
//            uac.setState(Status.LOGIC_Y);
//            uac.setUpdateTime(new Date());
//            uac.setThirdTradeNo(trade_no);
//            userAccountChargeRepository.save(uac);
//            userAccountService.onUserAccountAdd(uac.getUserId(),uac.getAmount(),Status.income,"支付宝充值 单号:"+outTradeNo);
//            return success;
//        }else {
//            log.error("支付状态已修改，无需重新操作！");
//            return fail;
//        }
//    }



    @Transactional(rollbackFor = Exception.class)
    public String alipayNotifyTradeSuccess(String outTradeNo,String tradeNo){
        // 我方订单号
        log.info("outTradeNo={},tradeNo={}",outTradeNo,tradeNo);
        UserAccountCharge thirdTrade = userAccountChargeRepository.findByThirdTradeNo(tradeNo);
        if(null!=thirdTrade){
            log.warn("三方订单号 thirdTradeNo充值记录已存在，无需入账操作！tradeNo={}",tradeNo);
            return fail;
        }


        UserAccountCharge uac = userAccountChargeRepository.findByOutTradeNo(outTradeNo);
        if(null==uac){
            log.warn("UserAccountCharge 充值记录不存在！outTradeNo={}",outTradeNo);
            return fail;
        }

        if(StringUtil.equals(uac.getState(),Status.LOGIC_N)){
            log.info("AliPayServiceImpl.alipayNotifyTradeSuccess");
            UserAccount account = userAccountDao.findUserAccountUseId(uac.getUserId());
            if(null == account){
                log.error("updateUserAccountChargeWithNotifyWithAlipay 充值账户信息不存在! userId=[{}]",uac.getUserId());
                return "fail";
            }
            uac.setState(Status.LOGIC_Y);
            uac.setUpdateTime(new Date());
            uac.setThirdTradeNo(tradeNo);
            userAccountChargeRepository.save(uac);
            userAccountService.onUserAccountAdd(uac.getUserId(),uac.getAmount(),Status.income,"支付宝充值 单号:"+outTradeNo);
            return success;
        }else {
            log.warn("支付状态已修改，无需重新操作！");
            return fail;
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public String tradeQuery(String outTradeNo) {

        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        AlipayTradeQueryModel model = new AlipayTradeQueryModel();
        model.setOutTradeNo(outTradeNo); // 设置订单支付时传入的商户订单号
        List<String> queryOptions = new ArrayList<>();
        queryOptions.add("trade_settle_info");
        model.setQueryOptions(queryOptions);
        request.setBizModel(model);

        try {
            AlipayTradeQueryResponse response =  alipayClient.certificateExecute(request);
            log.info("AlipayTradeQueryResponse={}",response.getBody());
            if(response.isSuccess()){
               String tradeStatus = response.getTradeStatus();
               String tradeNo = response.getTradeNo();
               // 同步支付状态
               if("TRADE_SUCCESS".equals(tradeStatus)){
                  String status = alipayNotifyTradeSuccess(outTradeNo,tradeNo);
                  log.info("alipayNotifyTradeSuccess status={}",status);
               }
            }
            return  response.getBody();
        } catch (AlipayApiException e) {
            e.printStackTrace();
            return e.getMessage();
        }

    }

    private String qrcodeImg(String qrcode){
        return sysConstant.getShareQrcode()+"?url="+ StringUtil.encode(qrcode,"utf-8");
    }


    /**
     * 参考文档 https://opendocs.alipay.com/open/8ad49e4a_alipay.trade.precreate?scene=2ae8516856f24a5592194d237f3f235d&pathHash=d18bff53
     * */
    @Override
    public JSONObject alipayPreCreate(String outTradeNo) throws AlipayApiException {
        log.info("alipayPreCreate outTradeNo = {}",outTradeNo);
        UserAccountCharge uac = userAccountChargeRepository.findByOutTradeNo(outTradeNo);
        ValidationUtil.requireNotNull(uac,"充值记录不存在！");
        JSONObject data = new JSONObject();
         if(Status.LOGIC_N == uac.getState()){
             AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
             request.setNotifyUrl(sysConstant.getAlipayNotifyUrl());
             JSONObject bizContent = new JSONObject();
             bizContent.put("out_trade_no", uac.getOutTradeNo());
             bizContent.put("total_amount", uac.getAmount());
             bizContent.put("subject", uac.getRemarks());
             bizContent.put("product_code","QR_CODE_OFFLINE");
             log.info("alipayPreCreate bizContent = {}",bizContent.toString());
             request.setBizContent(bizContent.toString());
             AlipayTradePrecreateResponse response = alipayClient.certificateExecute(request);

             if(response.isSuccess()){
                 data.put("charge",uac);
                 data.put("out_trade_no",response.getOutTradeNo());
                 data.put("qrcode",response.getQrCode());
                 data.put("src",qrcodeImg(response.getQrCode()));
             } else {
                 log.warn("AliPayServiceImpl.alipayPreCreate 支付失败 outTradeNo = {} ",outTradeNo);
             }
             return data;
         }else {
             throw ApiError.Type.LOGIC_ERROR.toException("充值状态异常！");
         }



    }

    //  https://uniapp.dcloud.io/tutorial/app-payment-alipay.html#%E5%BA%94%E7%94%A8%E5%86%85%E5%8F%91%E8%B5%B7%E6%94%AF%E4%BB%98
    //  https://opendocs.alipay.com/open/204/105465/#%E7%89%B9%E6%AE%8A%E8%AF%B4%E6%98%8E%EF%BC%88%E5%BE%88%E9%87%8D%E8%A6%81%EF%BC%89
    /**
     * // 参数说明 https://opendocs.alipay.com/open/00dn77
     * app 支付
     * app_id=2015052600090779&
     * biz_content=%7B%22timeout_express%22%3A%2230m%22%2C%22seller_id%22%3A%22%22%2C%22product_code%22%3A%22QUICK_MSECURITY_PAY%22%2C%22total_amount%22%3A%220.02%22%2C%22subject%22%3A%221%22%2C%22body%22%3A%22%E6%88%91%E6%98%AF%E6%B5%8B%E8%AF%95%E6%95%B0%E6%8D%AE%22%2C%22out_trade_no%22%3A%22314VYGIAGG7ZOYY%22%7D&
     * charset=utf-8&
     * method=alipay.trade.app.pay
     * &sign_type=RSA2
     * &timestamp=2016-08-15%2012%3A12%3A15&
     * version=1.0&
     * sign=MsbylYkCzlfYLy9PeRwUUIg9nZPeN9SfXPNavUCroGKR5Kqvx0nEnd3eRmKxJuthNUx4ERCXe552EV9PfwexqW%2B1wbKOdYtDIb4%2B7PL3Pc94RZL0zKaWcaY3tSL89%2FuAVUsQuFqEJdhIukuKygrXucvejOUgTCfoUdwTi7z%2BZzQ%3D
     * 参考 ： https://opendocs.alipay.com/open/54/106370
     * */
    @Override
    public JSONObject alipayPreCreateApp(String outTradeNo) {
        UserAccountCharge uac = userAccountChargeRepository.findByOutTradeNo(outTradeNo);
        ValidationUtil.requireNotNull(uac,"充值记录不存在！");
        JSONObject data = new JSONObject();
        if(Status.LOGIC_N == uac.getState()){
            try {
                AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
                AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
                String totalAmount = String.valueOf(NumberUtil.formatMoney(uac.getAmount(),null));
                log.info("alipayPreCreateApp Subject = {}",uac.getRemarks());
                log.info("alipayPreCreateApp body = 用户充值!");
                log.info("alipayPreCreateApp outTradeNo = {}",outTradeNo);
                log.info("alipayPreCreateApp setTimeoutExpress = {}",uac.getUserId());
                log.info("alipayPreCreateApp productCode = {}","QUICK_MSECURITY_PAY");
                log.info("alipayPreCreateApp totalAmount = {}",totalAmount);

                model.setSubject(uac.getRemarks());
                model.setBody("用户充值!"); // 花千束用户系统充值。
                model.setOutTradeNo(outTradeNo);
                model.setTimeoutExpress("30m");
                model.setProductCode("QUICK_MSECURITY_PAY"); // 销售产品码，商家和支付宝签约的产品码，APP支付功能中该值固定为： QUICK_MSECURITY_PAY
                model.setTotalAmount(totalAmount);
                request.setNotifyUrl(sysConstant.getAlipayNotifyUrl());
                request.setBizModel(model);
                AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
                if(response.isSuccess()){
                    String body = response.getBody();
                    String thirdTradeNo =  response.getOutTradeNo();
                    log.info("response body = {}",body);
                    data.put("orderInfo",body);
                    data.put("charge",uac);
                    data.put("out_trade_no",thirdTradeNo);
                }else {
                    log.warn("AliPayServiceImpl.alipayPreCreateApp 支付失败 outTradeNo = {} ",outTradeNo);
                }

            } catch (AlipayApiException e) {
                throw ApiError.Type.LOGIC_ERROR.toException(e.getMessage());
            }
        }
        return data;
    }
}
